查看原文
其他

【第762期】CSS最佳实践——成为CSS忍者的十四步(上)

安生 前端早读课 2019-09-18

前言
本文来自@安生的翻译分享。本文有两篇,本文是上,下篇在第二条。

正文从这开始~

就算是专业的Web开发者,可能也很难管理好CSS。在这个系列里,你将了解十四条关于CSS的最佳实践。在第一部分,你将学习如何掌握CSS特殊的层次结构,你会发现声明和ID选择器的危险,也会学习到过高优先级选择器带来的代价,最后你还会学习如何规避浏览器带来的不一致性。让我们开始学习吧。

第一条:掌握CSS特殊的层次结构

让我们从最艰难的一步开始。如果你想要成为一个CSS忍者,那么这是你必须掌握的,即便你不想成为忍者,也至少应该了解它。如果你只是想在同事朋友面前吹嘘一下,那么这块知识你一定要懂。有大量的人自称他们是Web开发者或者Web设计人员。

经常被忽略的基础知识

有趣的是,很多人对这个话题一无所知。这些人搭建了网站或者Web应用却不知道CSS是怎么工作的。他们知道一些层叠的知识,或者浏览器如何阅读选择器的(从右到左)。想象一下你认识一个对汽车的认知还不错的人,但你会让这个人给你造一辆车吗?恐怕不会。

不过如果你需要让人给你搭一个网站,你就需要寻找一个专业人士了。如果你同意我的话,那么真正专业的人士是会想去掌握好他的手艺的人。这种人会着迷于任何一个细节。如果CSS层次就是其中一个细节呢?或者是一个CSS最佳实践呢?那么,忽略这个细节的人就不能称之为专业人士了。

如果你想变得专业,你必须学习它,而如果你想成为忍者,你必须掌握它。你需要了解CSS的任何一个特性。当一个小孩问你,你需要能解释得出来,虽然不太可能发生。当然,你潜在的客户或者老板可能会问你关于这方面的东西。这个话题就是一个测试知识点的很好方式。

正如讨论过的,很多开发者对CSS特殊的层次结构知之甚少。因此这个问题可以说是帮助雇主们用来找到人才的好方法。若在网上向自由职业者提出这个问题,有多少人能够回答呢?

CSS特殊层次结构的困难之处

那么既然它如此重要,为什么它是CSS最容易被忽略的部分之一呢,而且为什么极少的CSS实践中会提及到?大概是因为你可能需要做一些数学运算。在这个层次结构中,每个CSS选择器都有一些特定的值。而且当你组合起选择器时,这些值会增加。因此简单的元素选择器(如a)比两个元素的选择器(如a span)的层次低。

通配符选择器它的值是最低的,几乎等于零。可以说所有的选择器都优先于它。排在后面的是元素选择器,它的值是1。然后是带有伪元素的元素,这个结合起来值是2。一直如此下去。最高值是元素选择器、ID选择器、class选择器再加上一个元素选择器的组合,这个组合的值是112。一个ID选择器的值差不多就是100了。(这段不大懂得话详见下表)

这里提供一个CSS特殊层次结构的概述。下边有个简单的表格可以帮助你快速找到层次,不用你自己去计算。如果你想要更深入了解的话,,不然你经常会需要回看这个表格。

CSS层次特性表:

第二条:避免使用声明

第二条实践和层次结构也有关系。接下来两条也是如此。我希望这会让你知道特殊的层次结构的重要性。言归正传,这条实践就是永远不要使用!improtant声明。为什么我会把杜绝!improtant放在CSS的最佳实践里呢。原因是因为它会导致你不能避免的恶性循环。

惹祸上身

想象下你和一个用!improtant声明的人工作在一块。你不得不再次用!imprtant声明来覆盖样式。你能怎么办呢?你有几个方案可供选择。第一你可以冒险移除你同事用的!improtant声明,后果是可能会破坏掉一些东西,你需要测试保证移除完所有东西依旧运行良好。但是这会花费很多时间。那么需要考虑下值不值得这样去做。第二个选择是运用你的CSS层次结构知识。解决这个声明的办法就是提高选择器的层级。假设你的同事是用一个span元素加上一个类名,这意味着你需要的是比一个class选择器更高的级别,这个值是10。你可以有几种选择实现。第一种是用两个元素选择器和一个class选择器。第二种是用一个ID选择器。第三种是元素选择器+ID选择器+类选择器+元素选择器。但你在接下来会认识到用ID不是CSS的最佳实践,所以你会排除这个选项,所以这意味着你不得不用两个元素选择器加上一个类选择器,否则你会违背其他的CSS最佳实践。

解决!improtant问题

我所举的例子可能看起来不算什么大问题。但当发现你不得不再次覆盖!improtant时会发生什么状况?这就是使用improtant的问题所在。前一个总是会传染给下一个。这就是我所说的恶性循环。你用了一个后很快你会不得已使用另一个。所以我相信唯一的解决办法就是不要使用!improtant。

处理这个声明的方式类似于对待毒品。最好的办法就是坚持CSS最佳实践然后永远不要起这个头。否则就是自找麻烦。这也是我鼓励你使用 的原因。因为你可能很容易又会忘了这条实践。所以使用一些工具来测试你的代码是有效良好的。而且如果你使用Gulp,你可以使用或者,只要力所能及都应该实现自动化。

第三条:不要使用ID

样式化元素时千万不要用ID。为什么说它属于CSS最佳实践呢?第一,ID是不可复用的,你只能在一个页面中用一个特定的ID元素。所以如果你想要在同一个页面样式化更多的元素,你需要使用更多的ID和更多行的CSS。第二,这是恶性循环的开始,我又要扯到CSS层次结构了。我们在前边的!improtant中有提到这个。第三,对于ID的争议是它通常用来指特定的元素,那么你就不可能让你的CSS变得简短又可复用。让样式太过特制化不是个好主意。相反的你应该让样式更具抽象和通用性。这可以帮助你重复地使用同一个样式。如果你在每个页面都用了超过一个特定的ID,那么可复用的CSS这个目标就不可能实现。

那么性能呢?

确实ID选择器的运行速度比class选择器要快。如果你定义了1000条规则,ID的性能会快。这是在你只在一个页面定义了一个ID选择器的情况下发生的,所以这并不是什么显著的性能优势。而且你只有在至少定义了1000规则之后才能获得这个优势,对于小项目来说这通常是一个还蛮大的数字。

我们还必须考虑的另一件事是额外的ID选择器会带来什么性能影响。==理论上当你添加任何ID选择器时,性能优势其实已经没有了。==而且如果你想获得任何性能优势的话,你不能在ID后边添加其他选择器。如果添加了像class或者元素选择器会发生什么呢?浏览器会从右到左阅读CSS,这意味着后边添加的选择器会首先被读取到,ID的速度优势也就被冲击掉了。

结论就是性能提升的唯一途径必须通过纯ID的选择器。同时你需要有足够多的CSS规则让优势显现。既然1000条规则可以有一毫秒的优势,那么你应该把目标放在100,000条规则上。这个大概可以给到100毫秒的优势。另外的事就是浏览器扫描渲染这么多CSS规则需要的时间。所以你应该避免使用ID为妙。

什么时候适合使用ID

在进入下一条实践前我先再说多一点。我是主张从你的CSS或者SASS中摆脱掉ID,但这不意味着你需要完全地从HTML标记中移除掉它。ID有一个具体的用例,就是使用到JS。正如讨论过的ID更快,所以能用来提升你的JS速度,同样的JS有个getElementByID()方法。

这个方法用来获取带有ID的元素,你可以使用ID作为唯一标识符来赋给需要额外功能的元素。这样做的另一个好处就是分离CSS和JS。当你从一个元素中去掉class时,你不用担心会破坏掉JS。所有你的JS只需要关联到ID即可。但是我还是想说我并不喜欢使用ID。

当我用到JS绑定时,我会使用带有”js-“前缀的class。这帮我区分哪些类是用于样式哪些是用于JS。现在我只会在一种状况下使用JS,在通过href属性给页面中某个元素绑定锚标记的时候。这样用户点击锚标记时页面会滚动到特定的区域。除了这个例子我不认为其他地方有需要使用到ID。

第四条:避免层次过高的元素

我保证这是最后一条关于CSS层次结构的最佳实践。层次过高的元素是什么意思?就是你给一个元素赋予了过多复杂的选择器。假设你想要一个锚标记表现得像一个按钮,符合最佳实践的做法是使用像btn类的东西,你的CSS或者SASS样式表可能就会包含像.btn {...}的代码。

当你使用了这个选择器,可能就会有类似a.btn{...}的代码,更极端点之后会变成a.btn.btn-big.btn-primary{...}。重点就是使用元素选择器变得没有必要。这同样适用于其他附加的类。你完全可以只用.btn类。所以避免使用层次过高的选择器可以有三个理由,一是你会想压缩的CSS大小写更少的CSS,和你要想要提高选择器的性能。

使用层次过高的元素的问题

我多次提到浏览器阅读CSS是从右到左。同时浏览器也在选择位于每个选择器后的元素。比如aricle h1{...},浏览器会先寻找所有h1标签,然后寻找所有内嵌在article标签里的h1标签。那么按钮的例子呢,浏览器会先寻找带有.btn-primary的元素,然后是同时带有.btn-primary.btn-big的元素。a.btn选择器同理。

综上所述,浏览器需要四个周期来呈现一个按钮。这高效得了吗?想象下你为了买些小东西会跑四趟超市吗?你当然会一次性买齐所有的吧。因此浏览器若在一个周期内完成,按钮的渲染才不会浪费时间。

网站变得更快可以提升用户体验,避免层次过高的元素会让浏览器渲染CSS更快些。更快的CSS渲染意味着你的站点会加载得更快。这就是你的目标。所以避开层级过高的元素意味着实现良好的用户体验。

第五条:reset还是normalize

思考下这个问题,当你开始一个新项目,你会先重置所有的元素的默认样式吗?如果没有的话我建议你把这部分加入你的工作流程里去。为什么呢?不同的浏览器会试图以不同的方式渲染一些CSS样式。这导致了或大或小的不一致设计。结果就是你的网站在Chrome,Firefox,Edge都会看起来有点不一样。试想下当你在客户端打开你的站点时发现布局乱套了。

你可以通过让浏览器渲染一致来解决这个问题。有两件事是你可以做的,一,自己手动重置所有元素,这可能会花费一些时间。如果每个项目都这样,可能并不高效。那么第二种方式就是使用预制的CSS样式表,把重置的样式表放在你主要的样式表前边即可。

reset还是normalize

当你选择第二种方式时,你需要考虑多一件事。你会采用哪种样式表来使浏览器呈现一致?目前有两种样式表可选,Nicolas Gallagher和Jonathan Neal写的或Eric A. Meyer写的。

这两种样式表是不同的,它们遵循不同的方法来移除浏览器的不一致性。Normalize只着眼于常规正确的样式;同时旨在保留默认样式,没有完全移除它们。它包含了一些小的修正来提高可用性。它也相对来说更模块化些,你可以提取或删除你不需要的部分。

Reset样式表则不太一样。它通过移除所有的样式来达成同质化的视觉样式,给几乎所有元素设定了广泛性的默认样式。它除去了所有的样式像粗体斜体等等。结果就是strongemspan看起来都差不多。从这个角度讲,reset就像一个大锤子,normalize则像一把手术刀。reset坚决地重置所有东西,normalize则是重置需要重置的。

因此这些样式表的代码和文件大小也是不同的。当然这些区别并不是很重要,但是它们是确实存在的。不管怎样,你应该选择哪个呢?看你更喜欢哪种方式了。如果你想要一个彻彻底底的重置,就选择reset。如果不需要那么极端的话就选择normalize。别忘了在normalize里添上些可用性的改进。我个人是偏爱Normalize的。

第六条:别重置所有东西

假定你同意重置了,但不要急于下载运行。这并不和上一条矛盾。你需要考虑清楚你是不是真的需要这个东西。无论是normalize还是reset,都包含了大量你可能不会运用到你的项目里的元素。因此没有必要让这个代码扩大你的CSS。

我的建议同时也是CSS最佳实践的第六条,是去定制预制的样式表。你需要选择你会用到的样式。当然,少数的额外几行CSS并不会对性能或者文件大小有什么太大影响。但是这不代表你可以浪费资源。如果想要用户体验良好,你需要利用一切机会去,这就是其中一个。

要记得所有这些样式表是会在很多种不同状况下工作的,这意味着你项目中一半的代码是没有用的。同时你个人的编码风格可能会覆盖掉一些这样的代码,这些重复性的东西是可以删除的。另一个解剖和定制样式表的原因是能得到更好地理解,当你分离reset或者normalize时,你可以清楚看到原本是什么东西。

结果就是你会知道它们是怎么工作的。这些样式表是由专业的Web开发者维护的。光是阅读源码和进行运用你就可以学习到很多东西。也可能帮助你找到更适合自己的样式表。

不要想CSS最佳实践了

这就是今天我带给你的所有CSS最佳实践。我相信这六条会帮助你提升你的CSS代码。让我们快速回顾一下,第一,掌握CSS特殊的层次结构。这是CSS经常被忽略的一部分。但是你能看到今天许多最佳实践都和它有关。第二,避免使用improtant声明,同时不要使用ID进行样式书写。这两件事可以避免恶性循环。

之后是避免层级过高的元素。它会让浏览器执行过多渲染你样式的不必要周期。这会降低性能和带来不佳的用户体验。最后是使用reset或者normalize样式表来避免浏览器的不一致。但要确保根据你具体的状况来量身定制。不然的话就会让你的CSS变得冗杂。

关于本文
译者:@安生
原文:


每天早读,三万同行相伴成长
欢迎投稿:181422448@qq.com

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存